#define DOHOME_LOG_LVL          DOHOME_LOG_LVL_INFO
#define DOHOME_LOG_TAG          "dohome_hal_ble"

#include <dohome_log.h>
#include "dohome_hal_ble.h"
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

#include "wm_bt_def.h"

#define printf(...)
typedef unsigned char u8_t;
typedef signed char s8_t;
typedef unsigned short u16_t;
typedef int ssize_t;

static unsigned char doit_port_inited = 0;
static unsigned char ble_enabled = 0;
static unsigned char scan_enabled = 0;
static unsigned char key_scan_enabled = 0;
static unsigned char adv_enabled = 0;

static struct bt_gatt_attr *notify_attrs;

static dohome_bt_param_t *bt_param;
static uint16_t g_dohome_bt_conn_id = 0;

static dohome_ble_data_buf_t dohome_adv;
static dohome_ble_data_buf_t dohome_scan_resp;

static dohome_bt_scan_odm_data_cb_t scan_odm_data_cb = NULL;

#define BT_UUID_DOLP_SER      BT_UUID_DECLARE_16(0x1910)
#define BT_UUID_DOLP_WRITE    BT_UUID_DECLARE_16(0x2b11)
#define BT_UUID_DOLP_NOTIFY   BT_UUID_DECLARE_16(0x2b10)

/* Window and Interval are equal for continuous scanning */
#define DOHOME_SCAN_INTERVAL_MS 60
#define DOHOME_SCAN_WINDOW_MS   30
#define NAME_LEN 			    30
#define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5)
#define DOHOME_SCAN_INTERVAL    ADV_SCAN_UNIT(DOHOME_SCAN_INTERVAL_MS)
#define DOHOME_SCAN_WINDOW      ADV_SCAN_UNIT(DOHOME_SCAN_WINDOW_MS)

#define BLE_GAP_EVENT_CONNECT               0
#define BLE_GAP_EVENT_DISCONNECT            1

static void bt_enable_cb(int err);

/* ble attr write/notify handle */
static uint16_t g_ble_demo_attr_indicate_handle = 0;
static uint16_t g_ble_demo_attr_write_handle = 0;
static uint16_t g_ble_demo_conn_handle = 0;
static uint8_t recv_data_buf[300] = {0};

dohome_get_mac_cb_t get_mac_cb;

void wm_ble_state_changed(tls_bt_state_t stat)
{
	if (stat == WM_BT_STATE_ON) {
		bt_enable_cb(0);
	} else if (stat == WM_BT_STATE_OFF) {
		DOHOME_LOG_W("BLE state changed to OFF\n");
	}
}

void dohome_hal_ble_connected(int conn_handle)
{
	DOHOME_LOG_I("BLE client connected\n");
    if(!doit_port_inited){
        return;
    }
	memset(recv_data_buf, 0, 300);
	g_ble_demo_conn_handle = conn_handle;
	if (bt_param->cb) {
        bt_param->cb(g_ble_demo_conn_handle, DOHOME_BT_EVENT_CONNECTED, NULL);
    }
}

void dohome_hal_ble_disconnected(void)
{
	DOHOME_LOG_I("BLE client disconnected\n");
	if (bt_param->cb) {
        bt_param->cb(0, DOHOME_BT_EVENT_DISCONNECTED, NULL);
    }
}

static void le_param_updated(struct bt_conn *conn, u16_t interval,
			     u16_t latency, u16_t timeout)
{
	DOHOME_LOG_I( "LE conn param updated: int 0x%04x lat %d to %d", interval, latency, timeout);
}
static ssize_t recv_cb(struct bt_conn *conn,
                   const struct bt_gatt_attr *attr, const void *buf,
                   u16_t len, u16_t offset, u8_t flags)
{
	if(!doit_port_inited){
        return OPRT_COM_ERROR;
    }
    // DOHOME_LOG_I( "write length %d   offset: %d", len, offset);
    // blog_info_hexdump("data", (uint8_t *)buf, len);
    DOHOME_LOG_D("dohome_bt_msg_cb buf->len %d\r\n",len);
    if (bt_param->cb) 
    {
        dohome_ble_data_buf_t dh_ble_buf;
        dh_ble_buf.data = (DOHOME_UCHAR_T *)buf;
        dh_ble_buf.len = len;
        DOHOME_LOG_D("recv_cb &dh_ble_buf %p\r\n",&dh_ble_buf);
        bt_param->cb(g_ble_demo_conn_handle, DOHOME_BT_EVENT_RX_DATA, &dh_ble_buf);
    }
    return len;
}

void dohome_hal_ble_recv_data(uint8_t data, int data_len)
{
	printf("~~> recv: %s\n", data);
	if (strlen(recv_data_buf)+data_len > 300) {
		memset(recv_data_buf, 0, 300);
		printf("~~> reset\n");
	}
	uint8_t start_addr = recv_data_buf + strlen(recv_data_buf);
	memcpy(start_addr, data, data_len);
	recv_cb(NULL, NULL, data, data_len, 0, 0);
}

void dohome_hal_set_mac_cb_func(dohome_get_mac_cb_t f){
	get_mac_cb = f;
}

static void bt_enable_cb(int err)
{
    DOHOME_LOG_I("bt_enable_cb %d \n",err);
    if (!err) {
		printf("DOHOME_BT_EVENT_BLEENABLED bt_param->cb %p\n",bt_param->cb);
		if (bt_param != NULL) {
			if (bt_param->cb) {
				bt_param->cb(0, DOHOME_BT_EVENT_BLEENABLED, NULL);
			}
		}
    }
}

int dohome_hal_bt_port_init(dohome_bt_param_t *para)
{
	DOHOME_LOG_I("dohome_hal_bt_port_init\n");
	if (NULL == para) {
        return OPRT_OS_ADAPTER_INVALID_PARM;
    }
	if(doit_port_inited)
	{
		DOHOME_LOG_I("dohome_hal_bt_port_init enabled already\n");
		return OPRT_OK;
	}
	tls_bt_status_t status = demo_bt_enable();
	if((status != TLS_BT_STATUS_SUCCESS) &&(status != TLS_BT_STATUS_DONE) ) {
		return OPRT_COM_ERROR;
	}
	bt_param = para;
	if(get_mac_cb) {
		DOHOME_UINT8_T bt_mac[6] = {0};
		tls_get_bt_mac_addr(bt_mac);
		get_mac_cb(bt_mac,6);
	}
	doit_port_inited = 1;
	
    return OPRT_OK;
}

/**
 * @brief 用于释放化蓝牙资源
 * 
 * @return int 0=成功，非0=失败
 */
int dohome_hal_bt_port_deinit(void)
{
    printf("dohome_hal_bt_port_deinit\n");
	if(doit_port_inited == 0) {
		printf("dohome_hal_bt_port_deinited already\n");
		return OPRT_OK;
    }
	
	//tls_ble_server_demo_api_deinit();
	
	tls_bt_status_t status = demo_bt_destroy();
	if((status != TLS_BT_STATUS_SUCCESS) &&(status != TLS_BT_STATUS_DONE) ) {
		return OPRT_COM_ERROR;
	}
	
	doit_port_inited = 0;
    return OPRT_OK;
}

/**
 * @brief 用于断开蓝牙连接
 * 
 * @return int 0=成功，非0=失败
 */
int dohome_hal_bt_gap_disconnect(uint16_t conn)
{
    return OPRT_OK;
}

/**
 * @brief 用于发送蓝牙数据
 * 
 * @param[in]       data     发送数据
  * @param[in]      len      数据长度
 * @return int 0=成功，非0=失败
 */
int dohome_hal_bt_send(uint16_t conn,const unsigned char *data, const unsigned char len)
{
	int rc = tls_ble_server_demo_api_send_msg(data, len);
	DOHOME_LOG_D("~~> ble notify back: %s, len=%d\n", data, len);
	if (rc != 0) {
		DOHOME_LOG_E("~~> notify data error: %d\n", rc);
		return OPRT_COM_ERROR;
	}
    return OPRT_OK;
}

/**
 * @brief 用于重置蓝牙广播内容
 * 
 * @param[in]       adv
 * @param[in]      scan_resp
 * @return int 0=成功，非0=失败
 */

int dohome_hal_bt_reset_adv(const dohome_ble_data_buf_t *adv, const dohome_ble_data_buf_t *scan_resp)
{

	DOHOME_LOG_I("\nreset adv\n");
    return OPRT_OK;
}
struct bt_ad {
	const struct bt_data *data;
	size_t len;
};
static int dohome_depend_set_ad(u16_t hci_op, const struct bt_ad *ad, size_t ad_len)
{
	return 0;
}
/**
 * @brief 用于启动蓝牙广播
 * 
 * @return int 0=成功，非0=失败
 */
int dohome_hal_bt_start_adv(void)
{
	uint8_t tmp_i = 0;
	DOHOME_LOG_I("\ninit adv\n");
    while(tmp_i < (bt_param->adv.len)) {
        //printf("0x%02x ",*(bt_param->adv.data+tmp_i));
        tmp_i++;
    }
	printf("\n");
	printf("init scan_resp\n");
    while(tmp_i < (bt_param->scan_rsp.len))
    {
        printf("0x%02x ",*(bt_param->scan_rsp.data+tmp_i));
        tmp_i++;
    }
    printf("\n");

	DOHOME_UINT8_T bt_mac[6] = {0};
	tls_get_bt_mac_addr(bt_mac);
	get_mac_cb(bt_mac,6);
	memcpy(bt_param->adv.data+19, bt_mac, 6); //copy BT MAC
	//int rc = tls_ble_set_resp_data(bt_param->scan_rsp.data, bt_param->scan_rsp.len); //set scan response data, it must be setup first
	//rc = tls_ble_demo_adv(1, bt_param->adv.data, 31 /*bt_param->adv.len*/);
	tls_ble_server_demo_api_init(NULL, bt_param->adv.data, bt_param->adv.len, bt_param->scan_rsp.data, bt_param->scan_rsp.len); //init ble GATTS
	DOHOME_LOG_I("ble server ON, response data_len:%d\n", bt_param->scan_rsp.len);

	if (bt_param->cb) {
        bt_param->cb(g_dohome_bt_conn_id, DOHOME_BT_EVENT_ADV_READY, NULL);
    }
    // dohome_hal_bt_assign_scan(0);
    printf("dohome_hal_bt_start_adv end\n");

    return OPRT_OK;
}

/**
 * @brief 用于停止蓝牙广播
 * 
 * @return int 0=成功，非0=失败
 */
int dohome_hal_bt_stop_adv(void)
{
	int rc = tls_ble_demo_adv(0);
    return OPRT_OK;
}

/**
 * @brief 用于获取蓝牙信号强度
 * 
 * @param[out]       rssi
 * @return int 0=成功，非0=失败
 */
int dohome_hal_bt_get_rssi(signed char *rssi)
{
	if (NULL == rssi) {
        return OPRT_OS_ADAPTER_INVALID_PARM;
    }
	//todo
    return OPRT_OK;
}

/**
 * @brief 用于扫描蓝牙信标
 * 
 * @param[out]       rssi
 * @return int 0=成功，非0=失败
 */
int dohome_hal_bt_assign_scan(dohome_bt_scan_info_t *info)
{
	return 0;
}

static bool data_cb(struct bt_data *data, void *user_data)
{
	return true;
}


void coex_wifi_pta_forece_enable(int enable);

int dohome_hal_bt_odm_scan(dohome_bt_scan_odm_data_cb_t scan_cb)
{
    printf("dohome_hal_bt_filter_scan");

    return 0;
}

void dohome_hal_bt_scan_disable(void){
    
}

void dohome_hal_bt_scan_enable(void){
    
}